﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Security;
using elmah2.core.data;
using elmah2.core.interfaces;
using System.Collections;
using System.Configuration;
using elmah2.core.config;

namespace elmah2
{
  public class ErrorLogger : IHttpModule
  {
    private object loggerKey;
    private List<IErrorFilter> _filters;

    private string _appName = null;
    private string AppName
    {
      get
      {
        if (_appName == null)
          _appName = GetApplicationName();
        return _appName;
      }
    }

    public void Dispose()
    {      
      DisposeModule();
    }

    public void Init(HttpApplication app)
    {
      app.Error += (sender, e) => LogException(app.Server.GetLastError(), app.Context);
      GetLoggers(app.Context).ForEach(R => R.AddApplication(AppName));
      _filters = Filter.GetFilters();
    }

    public virtual void LogException(Exception ex, HttpContext context)
    {
      if (ex != null)
      {
        if (_filters != null)
        {
          foreach (IErrorFilter ief in _filters)
          {
            if (ief.FilterError(ex))
              return;
          }
        }

        Error error = new Error(ex, context);
        error.ApplicationName = AppName;

        List<IErrorLogger> loggers = GetLoggers(context);
        if (loggers == null || loggers.Count == 0)
          throw new Exception("Logger not found in config");

        foreach (IErrorLogger logger in loggers)
        {
          logger.LogError(error);
        }
      }
    }

    private List<IErrorLogger> GetLoggers(HttpContext context)
    {
      List<IErrorLogger> toreturn = null;
      if (loggerKey == null)
        loggerKey = new object();

      if (context != null)
      {
        toreturn = (List<IErrorLogger>)context.Items[loggerKey];
      }

      if (toreturn == null)
      {
        toreturn = Logger.GetLoggers();
        if (toreturn == null)
          throw new Exception("Log provider(s) missing");

        if (context != null)
        {
          context.Items[loggerKey] = toreturn;
        }
      }

      return toreturn;
    }

    private string GetApplicationName()
    {
      ApplicationSection config = (ApplicationSection)ConfigurationManager.GetSection("elmah2/application");
      return config.Name;
    }

    public virtual void DisposeModule()
    {
      _filters = null;
    }

    protected virtual bool SupportDiscoverability
    {
      get { return false; }
    }
  }
}
